/*******************************************************************/
/*    Copyright (c) 2008-2010 by Spatial Corp.                     */
/*    All rights reserved.                                         */
/*******************************************************************/
//#include "stdafx.h"
//#include <afx.h>

#include <locale.h>
#include <TCHAR.H>

#include "EBomXmlParser.h"

#ifdef XERCES_YES

#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/parsers/AbstractDOMParser.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/framework/XMLFormatter.hpp>

#if defined(XERCES_NEW_IOSTREAMS)
#include <iostream>
#include <fstream>
#else
#include <iostream.h>
#include <fstream.h>
#endif

XERCES_CPP_NAMESPACE_USE

EBomXmlParser::EBomXmlParser()
{
	m_TreeNode = NULL;

	// Initialize 06/16/2006 Bashi Add 
	XMLPlatformUtils::Initialize();
}

EBomXmlParser::~EBomXmlParser()
{
	if ( NULL != m_TreeNode )
	{
		DeleteAsmTreeNode( m_TreeNode );
		m_TreeNode = NULL;
	}

	// Terminate 06/16/2006 Bashi Add 
	XMLPlatformUtils::Terminate();
}

void EBomXmlParser::GetNodeAttributes( DOMNode* pNode, int& numOfChild, XMLCh* nodeName, XMLCh* refLinkId, double*& positionMatrix )
{
	//Get the name of the node
	DOMNamedNodeMap* pAttrMap = pNode->getAttributes();
	XMLCh* pNameCh = XMLString::transcode( "Name" );
	DOMNode* nameAttr = pAttrMap->getNamedItem( pNameCh );
	XMLString::release( &pNameCh );
	if ( nameAttr != NULL )
	{
		XMLString::copyString( nodeName, nameAttr->getNodeValue() );
	}

	//Get the number of child
	DOMNodeList* nodeList = pNode->getChildNodes();
	unsigned int idx = 0;
	while ( idx < nodeList->getLength() )
	{
		const XMLCh* pNodeName = nodeList->item( idx )->getNodeName();
		if ( XMLString::compareString( pNodeName, L"Child" ) == 0 )
		{
			numOfChild++;
		}
		idx++;
	}

	//Get filename and position matrix if this node has reflink and position 

	DOMNode* firstChild = pNode->getFirstChild();
	DOMNode* lastChild = pNode->getLastChild();
	for ( pNode = firstChild; pNode != lastChild; pNode = pNode->getNextSibling() )
	{
		const XMLCh* pNodeName = pNode->getNodeName();

		// Bashi 11/29/2004 Add
		if ( XMLString::compareString( pNodeName, L"#text" ) == 0 )
		{
			continue;
		}

		if ( XMLString::compareString( pNodeName, L"RefLink" ) == 0 )
		{
			//Get filename (include full path)
			DOMNode* refLink = pNode;
			pAttrMap = refLink->getAttributes();
			XMLCh* idStr = XMLString::transcode( "Id" );
			DOMNode* idAttr = pAttrMap->getNamedItem( idStr );
			XMLString::release( &idStr );

			if ( idAttr != NULL )
			{
				const XMLCh* RefLinkId = idAttr->getNodeValue();
				XMLString::copyString( refLinkId, RefLinkId ); // Bashi

				// 4/16/2014 mwu :  
			}
		}
		else if ( XMLString::compareString( pNodeName, L"Position" ) == 0 )
		{
			positionMatrix = new double[16];
			//Get child position
			DOMNodeList* matrixList = pNode->getChildNodes();
			for ( unsigned int idxChild = 0; idxChild < matrixList->getLength(); idxChild++ )
			{
				const XMLCh* childNodeName = matrixList->item( idxChild )->getNodeName();
				const XMLCh* textContent = matrixList->item( idxChild )->getTextContent();
				double value = ( float ) wcstod( textContent, NULL );

				// Bashi 11/29/2004 Add
				if ( XMLString::compareString( childNodeName, L"#text" ) == 0 )
				{
					continue;
				}

				if ( XMLString::compareString( childNodeName, L"V1" ) == 0 )
				{
					positionMatrix[0] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"V2" ) == 0 )
				{
					positionMatrix[1] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"V3" ) == 0 )
				{
					positionMatrix[2] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"V4" ) == 0 )
				{
					positionMatrix[4] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"V5" ) == 0 )
				{
					positionMatrix[5] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"V6" ) == 0 )
				{
					positionMatrix[6] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"V7" ) == 0 )
				{
					positionMatrix[8] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"V8" ) == 0 )
				{
					positionMatrix[9] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"V9" ) == 0 )
				{
					positionMatrix[10] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"T1" ) == 0 )
				{
					positionMatrix[12] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"T2" ) == 0 )
				{
					positionMatrix[13] = value;
				}
				else if ( XMLString::compareString( childNodeName, L"T3" ) == 0 )
				{
					positionMatrix[14] = value;
				}
			}
			positionMatrix[3] = 0.0f;
			positionMatrix[7] = 0.0f;
			positionMatrix[11] = 0.0f;
			positionMatrix[15] = 1.0f;
		}
	}
}

void EBomXmlParser::BuildAssemblyTree( DOMNode* pNode, EBomTreeNode*& pEBomNode, int nDepth )//Need recursive
{
	if ( pNode != NULL )
	{
		//Get information from pNode
		int numOfChild = 0;
		XMLCh nodeName[SIZE];
		memset( nodeName, 0, sizeof( nodeName ) );

		XMLCh refLinkId[SIZE*4];
		memset( refLinkId, 0, sizeof( refLinkId ) );

		double* positionMatrix = NULL;

		GetNodeAttributes( pNode, numOfChild, nodeName, refLinkId, positionMatrix );

		//new a EBomTreeNode node

		pEBomNode = new EBomTreeNode( numOfChild, nodeName, NULL, NULL, refLinkId, positionMatrix );

		if ( nDepth == 0 )//root
		{
			pEBomNode->SetSrcFileName( m_DocList[0].docFilePath );
		}
		else
		{
			int i = 0;
			for ( i = 0; i < m_DocList.size(); i++ )
			{
				if ( _tcslen(m_DocList[i].docIdentifier)>0 && _tcsicmp( refLinkId, m_DocList[i].docIdentifier ) == 0 )
				{
					if (_tcsicmp(m_DocList[i].docType,L"sab") ==0)
					{
						pEBomNode->SetFileName( m_DocList[i].docFilePath );
					}
					else //original
					{
						pEBomNode->SetSrcFileName( m_DocList[i].docFilePath );
					}
				}
			}
		}
		nDepth++;

		if ( positionMatrix )
		{
			delete[] positionMatrix;
			positionMatrix = NULL;
		}

		//Recursive
		DOMNodeList* childList = pNode->getChildNodes();
		int curSize = 0;
		for ( unsigned int i = 0; i < childList->getLength(); i++ )
		{
			DOMNode* node = childList->item( i );
			const XMLCh* pNodeName = node->getNodeName();
			if ( XMLString::compareString( pNodeName, L"Child" ) == 0 )
			{
				EBomTreeNode** ppChildList = pEBomNode->GetChilds();
				if ( NULL != ppChildList )
				{
					BuildAssemblyTree( node, ppChildList[curSize++], nDepth );
				}
			}
		}
	}
}

void EBomXmlParser::ParserXMLFile( const TCHAR* xmlFileName, const char* locale )
{
	const XMLCh* xmlFile = xmlFileName;

	bool doNamespaces = true;
	bool doSchema = true;
	bool schemaFullChecking = false;

	setlocale( LC_ALL, locale );

	try
	{
		if ( strlen( locale ) )
		{
			XMLPlatformUtils::Initialize( locale );
		}
		else
		{
			XMLPlatformUtils::Initialize();
		}
	}
	catch ( const XMLException& toCatch )
	{
		XERCES_STD_QUALIFIER cerr << "Error during initialization! Message:\n" << toCatch. getMessage() << XERCES_STD_QUALIFIER endl;
		return;
	}

	// Instantiate the DOM parser.

	XercesDOMParser* parser = new XercesDOMParser;
	parser->setDoSchema( doSchema );
	parser->setDoNamespaces( doNamespaces );	

	//Parser the xml file

	// wumin 2004.12.30
	//Modify the Encoding according to locale settings
	ModifyXMLEncoding( xmlFile, "chs" );

	try
	{
		parser->parse( xmlFile );//doesn't support Unicode filename/pathname?????
	}
	catch ( const XMLException& e )
	{
		XERCES_STD_QUALIFIER cerr << "An error occurred during parsing\n   Message: " << e. getMessage() << XERCES_STD_QUALIFIER endl;
	}
	catch ( const DOMException& e )
	{
		const unsigned int maxChars = 2047;
		XMLCh errText[maxChars + 1];

		XERCES_STD_QUALIFIER cerr << "\nDOM Error during parsing: '" << xmlFile << "'\n" << "DOMException code is:  " << e.code << XERCES_STD_QUALIFIER endl;

		if ( DOMImplementation::loadDOMExceptionMsg( e.code, errText, maxChars ) )
			XERCES_STD_QUALIFIER cerr << "Message is: " << errText << XERCES_STD_QUALIFIER endl;
	}
	catch ( ... )
	{
		XERCES_STD_QUALIFIER cerr << "An error occurred during parsing\n " << XERCES_STD_QUALIFIER endl;
	}

	//Read tree data

	XERCES_CPP_NAMESPACE::DOMDocument* doc = parser->getDocument();
	DOMNode* root = parser->getDocument();

	if ( NULL == doc )
	{
		return;
	}

	//Get document attribute
	DOMTreeWalker* walker = doc->createTreeWalker( root, DOMNodeFilter::SHOW_ALL, NULL, true );
	DOMNode* current = NULL;

	for ( current = walker->nextNode(); current != 0 ; current = walker->nextNode() )
	{
		const XMLCh* pNodeName = current->getNodeName();
		if ( XMLString::compareString( pNodeName, L"Document" ) == 0 )
		{
			EBomDocument docNode;
			{
				//Get Name
				DOMNamedNodeMap* pAttrMap = current->getAttributes();
				XMLCh* pNameCh = XMLString::transcode( "Name" );
				DOMNode* pNameAttr = pAttrMap->getNamedItem( pNameCh );
				XMLString::release( &pNameCh );
				if ( pNameAttr != NULL )
				{
					XMLString::copyString( docNode.docName, pNameAttr->getNodeValue() );
				}

				//Get Type
				DOMNamedNodeMap* pAttrib = current->getAttributes();
				XMLCh* pTypeCh = XMLString::transcode( "Type" );
				DOMNode* pTypeAttr = pAttrib->getNamedItem( pTypeCh );
				XMLString::release( &pTypeCh );

				if ( pTypeAttr != NULL )
				{
					XMLString::copyString( docNode.docType, pTypeAttr->getNodeValue() );
				}

				//Get Identifier
				XMLCh* pIdentifierCh = XMLString::transcode( "Identifier" );
				DOMNode* identifierAttr = pAttrMap->getNamedItem( pIdentifierCh );
				XMLString::release( &pIdentifierCh );
				if ( identifierAttr != NULL )
				{
					XMLString::copyString( docNode.docIdentifier, identifierAttr->getNodeValue() );
				}

				//Get FilePath
				XMLCh* pFilePathCh = XMLString::transcode( "FilePath" );
				DOMNode* filePathAttr = pAttrMap->getNamedItem( pFilePathCh );
				XMLString::release( &pFilePathCh );
				if ( filePathAttr != NULL )
				{
					XMLString::copyString( docNode.docFilePath, filePathAttr->getNodeValue() );
				}

				m_DocList.push_back(docNode);
			} // 12/22/2005 Bashi
		}
	}
	walker->release();

	//Create assembly tree structure
	 {
		DOMTreeWalker* walker = doc->createTreeWalker( root, DOMNodeFilter::SHOW_ALL, NULL, true );
		root = walker->getRoot();

		DOMNode* current = NULL;
		for ( current = walker->nextNode(); current != 0; current = walker->nextNode() )
		{
			const XMLCh* pRootNodeName = current->getNodeName();
			if ( XMLString::compareString( pRootNodeName, L"Root" ) == 0 )
			{
				//Get Root Name
				DOMNamedNodeMap* pAttrMap = current->getAttributes();

				XMLCh* pNameCh = XMLString::transcode( "Name" );
				DOMNode* nameAttr = pAttrMap->getNamedItem( pNameCh );
				XMLString::release( &pNameCh );
				if ( nameAttr != NULL )
				{
					XMLString::copyString( m_rootName, nameAttr->getNodeValue() );
				}

				//Create Assembly Tree
				BuildAssemblyTree( current, m_TreeNode, 0 );//Create assembly tree structure
				break;
			}
		}
		walker->release();
	}

	 delete parser;
	XMLPlatformUtils::Terminate();
}

void EBomXmlParser::ParserXMLFile( const char* xmlFileName, const char* locale )
{
	TCHAR fileName[SIZE*4];
	memset( fileName, 0, sizeof( fileName ) );
	mbstowcs( fileName, xmlFileName, sizeof( fileName ) );
	ParserXMLFile( fileName, locale );
}

void EBomXmlParser::DeleteAsmTreeNode( EBomTreeNode*& pAsmNode )
{
	EBomTreeNode** ppChildList = pAsmNode->GetChilds();
	int i = 0;
	for ( i = 0; i < pAsmNode->GetSize(); i++ )
	{
		if ( ppChildList )
		{
			DeleteAsmTreeNode( ppChildList[i] );
		}
	}
	delete pAsmNode;
	pAsmNode = NULL;
}

const TCHAR* EBomXmlParser::GetRootName()
{
	return ( m_rootName );
}

bool EBomXmlParser::ModifyXMLEncoding( const TCHAR* xmlFileName, const char* locale )
{
	char xmlFile[1024];
	memset( xmlFile, 0, 1024 );
	wcstombs( xmlFile, xmlFileName, 1024 );

	const char* oldEncoding = "ISO-8859-1";
	char newEncoding[20];

	if ( ( strcmp( locale, "chs" ) == 0 ) || ( strcmp( locale, "simplified-chinese" ) == 0 ) )
	{
		sprintf( newEncoding, "GB2312" );
	}
	else if ( ( strcmp( locale, "jpn" ) == 0 ) || ( strcmp( locale, "japanese" ) == 0 ) )
	{
		sprintf( newEncoding, "ISO-2022-JP" );
	}
	//	else
	//	{
	//		sprintf(newEncoding,"ISO-8859-1");
	//	}

	bool retval = false;

	size_t diffLength = strlen( newEncoding ) - strlen( oldEncoding );

	// 	CFile file(xmlFile, CFile::modeRead);
	// 	
	// 	long lenOfFile = file.GetLength();
	// 	char* buffer = NULL;
	// 	buffer = new char[lenOfFile+1];
	// 	memset(buffer, 0, lenOfFile);
	// 	file.Read(buffer, lenOfFile);
	// 	file.Close();
	// 
	// 
	// 	CString str(buffer);
	// 
	// 	if(str.Find(oldEncoding,0)!=-1 /*found*/ && diffLength != 0/*is different*/)
	// 	{
	// 		retval = true;
	// 
	// 		str.Replace(oldEncoding,newEncoding);
	// 
	// 		CFile newfile(xmlFile, CFile::modeCreate|CFile::modeWrite);
	// 
	// 		newfile.Write(str, lenOfFile+diffLength);
	// 		newfile.Close();
	// 	}

	// 	if (NULL != buffer)
	// 	{
	// 		delete[] buffer;
	// 		buffer = NULL;
	// 	}

	return retval;
}

#endif